package com.jcode.netty.codec;

import java.io.Serializable;
import java.nio.ByteBuffer;
import java.nio.charset.Charset;

import com.jcode.netty.protocol.Packet;
import com.jcode.netty.serialize.FastJsonSerializer;
import com.jcode.netty.serialize.Serializer;
import com.jcode.netty.serialize.SerializerFactory;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import io.netty.handler.codec.LengthFieldBasedFrameDecoder;

/**
 * @Desc
 * @Author dreajay
 * @DateTime 2016年11月17日 下午5:25:51
 */
public class NettyDecoder extends LengthFieldBasedFrameDecoder {
    public final static Charset charset = Charset.forName("UTF-8");

    private Serializer fastJsonSerializer = new FastJsonSerializer();

    public NettyDecoder() {
        super(1024 * 1024, 0, 4);
    }

    @Override
    protected Object decode(ChannelHandlerContext ctx, ByteBuf in) throws Exception {
        try {
            ByteBuf buf = (ByteBuf)super.decode(ctx, in);
            if (buf == null) {
                return null;
            }
            byte[] tmpBuf = new byte[buf.capacity()];
            buf.getBytes(0, tmpBuf);
            buf.release(); // 释放
            ByteBuffer byteBuffer = ByteBuffer.wrap(tmpBuf);
            return decode(byteBuffer);
        } catch (Exception e) {
            // 这里关闭后， 会在pipeline中产生事件，通过具体的close事件来清理数据结构
            // RemotingHelper.closeChannel(channel);
            return null;
        }
    }

    public Packet decode(ByteBuffer byteBuffer) throws Exception {
        // 报文总长度
        int length = byteBuffer.getInt();
        // 报文头长度
        int headerLength = byteBuffer.getInt();
        // 报文头内容
        byte[] headerData = new byte[headerLength];
        byteBuffer.get(headerData);
        Packet packet = fastJsonSerializer.deserialize(headerData, Packet.class);
        // 报文体长度=总长度-4个字节报文头长度-报文头长度
        int bodyLength = length - 4 - headerLength;
        if (bodyLength > 0) {
            // 报文体长度
            byte[] bodyData = new byte[bodyLength];
            byteBuffer.get(bodyData);
            packet.setBodyData(bodyData);
            Serializer serializer = SerializerFactory.getSerializer(packet.getSerializeType());
            Serializable body = serializer.deserialize(bodyData, Serializable.class);
            packet.setBody(body);
        }
        return packet;
    }

}
